package com.example.wuyeguanli.activity;

import androidx.test.core.app.ActivityScenario;
import androidx.test.espresso.IdlingRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.example.wuyeguanli.R;
import com.example.wuyeguanli.entiy.Facility;
import com.example.wuyeguanli.tools.ApiClient;
import com.example.wuyeguanli.tools.EspressoIdlingResource;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.IOException;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;

import static androidx.test.espresso.Espresso.onData;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
import static androidx.test.espresso.action.ViewActions.replaceText;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withSpinnerText;
import static com.example.wuyeguanli.activity.CustomViewActions.forceClick;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;

@RunWith(AndroidJUnit4.class)
public class FacilityBookingActivityTest {

    private static MockWebServer mockWebServer;
    private static String originalBaseUrl;

    @BeforeClass
    public static void setUpClass() throws IOException {
        originalBaseUrl = ApiClient.BASE_URL;
        mockWebServer = new MockWebServer();
        mockWebServer.start(8080);
        ApiClient.setBaseUrlForTesting(mockWebServer.url("/").toString());
    }

    @AfterClass
    public static void tearDownClass() throws IOException {
        if (mockWebServer != null) {
            mockWebServer.shutdown();
        }
        ApiClient.setBaseUrlForTesting(originalBaseUrl);
    }

    // 核心修正: 注册和注销IdlingResource
    @Before
    public void registerIdlingResource() {
        IdlingRegistry.getInstance().register(EspressoIdlingResource.getIdlingResource());
    }

    @After
    public void unregisterIdlingResource() {
        IdlingRegistry.getInstance().unregister(EspressoIdlingResource.getIdlingResource());
    }

    // 辅助方法: 加载设施列表的Mock响应
    private void enqueueFacilityListResponse() {
        String facilityListJson = "{\"state\":\"success\",\"error\":\"\",\"data\":[" +
                "{\"facilityId\":\"gym\",\"facilityName\":\"健身房\"}," +
                "{\"facilityId\":\"pool\",\"facilityName\":\"游泳池\"}" +
                "]}";
        mockWebServer.enqueue(new MockResponse().setBody(facilityListJson));
    }

    @Test
    public void testLoadFacilitiesAndSelect() {
        enqueueFacilityListResponse();
        ActivityScenario.launch(FacilityBookingActivity.class);

        // Espresso会因为IdlingResource等待网络请求完成。
        // UI更新可能仍有微小延迟，我们用一种更可靠的方式来验证。

        // 核心修正: 不再使用withSpinnerText检查默认项，而是直接检查Adapter中的第一项数据。
        // onData会等待Adapter数据加载完成。
        onData(allOf(is(instanceOf(Facility.class)), is(new Facility("gym", "健身房"))))
                .atPosition(0) // 检查第一项数据
                .check(matches(is(instanceOf(Facility.class)))); // 只要能找到就说明加载成功了

        // 模拟选择第二项 "游泳池"
        onView(withId(R.id.spinner_faclity)).perform(click());
        // onData的匹配目标是Adapter里的数据对象，而不是显示的字符串。
        // 我们需要匹配Facility对象的toString()方法返回的字符串。
        // 假设FacilityAdapter使用的是Facility对象的facilityName来显示文本。
        // onData(allOf(is(instanceOf(Facility.class)), hasToString(containsString("游泳池")))).perform(click());
        // 更可靠的方式是直接匹配对象
        onData(is(new Facility("pool", "游泳池"))).perform(click());


        // 验证选择成功
        onView(withId(R.id.spinner_faclity)).check(matches(withSpinnerText(containsString("游泳池"))));
    }

    @Test
    public void testBookingFacility_Success() throws InterruptedException {
        enqueueFacilityListResponse();
        mockWebServer.enqueue(new MockResponse().setBody("{\"state\":\"success\",\"error\":\"\",\"data\":\"F-TEST-001\"}"));
        mockWebServer.enqueue(new MockResponse().setBody("{\"state\":\"success\",\"error\":\"\",\"data\":null}"));

        ActivityScenario.launch(FacilityBookingActivity.class);

        onView(withId(R.id.telephone)).perform(replaceText("13800138001"));
        onView(withId(R.id.reason_text)).perform(replaceText("公司团建"), closeSoftKeyboard());

        // 核心修正: 直接点击，让Espresso自己处理滚动
        onView(withId(R.id.btn_submit)).perform(forceClick());
    }

    @Test
    public void testBookingFacility_Fail_TimeConflict() throws InterruptedException {
        enqueueFacilityListResponse();
        mockWebServer.enqueue(new MockResponse().setBody("{\"state\":\"success\",\"error\":\"\",\"data\":\"F-TEST-002\"}"));
        mockWebServer.enqueue(new MockResponse().setBody("{\"state\":\"error\",\"error\":\"预定失败：该时间段已被占用。\",\"data\":null}"));

        ActivityScenario.launch(FacilityBookingActivity.class);

        onView(withId(R.id.telephone)).perform(replaceText("13800138001"));
        onView(withId(R.id.reason_text)).perform(replaceText("再次预定"), closeSoftKeyboard());

        // 核心修正: 直接点击，让Espresso自己处理滚动
        // `click()` 操作本身就包含了一个检查，它会尝试滚动到视图。
        // 我们之前的 `scrollTo()` 是多余的，有时反而会因为复杂的布局而失败。
        onView(withId(R.id.btn_submit)).perform(forceClick());

        onView(withId(R.id.btn_submit)).check(matches(isDisplayed()));
    }
}